﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using com.ReinforceLab.AudioModem.SignalTrace;

namespace com.ReinforceLab.AudioModem.LinkLayer
{
    /// <summary>
    /// FSK バイトデータ伝送
    ///   ボーレート: 2400， 4800， 9600 のいずれか
    ///   変調方式: FPSK    
    ///   ビットオーダー: LSb-first (先頭は最下位ビット) 
    ///   同期方式: キャラクタ同期(0x7e)， エスケープキャラクタは(0x7d)
    ///   
    /// キャリア検出: Carrier未検出条件は、10秒以上の通信がないこと。
    /// レイテンシ: 規定せず。(タイマ割り込み周期は100msecをデフォルト値に。レイテンシ=送信データ時間 (16バイトで14msec@9600bps)+ (送受信遅れ(OpenAL)+タイマー(100msec) ~ 200msec程度)
    /// </summary>
    /*public class FSKAsyncModem : IModem
    {
        #region Variables
        const int _samplePerCycle = 8;
        const int _sampleDuration = 100;  // OpenAL buffer read timer period

        readonly IAudioPHY      _socket;
        readonly BitDemodulator   _demodulator;
        readonly Modulator     _modulator;
        readonly AsyncByteReader _dataRecovery;
        
        readonly LowPassFilter  _sincFilter;
        readonly CDCFilter   _cdcFilter;
        readonly SliceFilter _sliceFilter;        
        readonly PulseWidthCounterFilter _countFilter;

        readonly int _baudRate;
        readonly int _samplingRate;

        System.Threading.Thread _thread;

        ITracer _audioSignal;
        ITracer _sincSignal;
        ITracer _cdcSignal;
        ITracer _sliceSignal;
        ITracer _countSignal;
        ITracer _demodSignal;        
        #endregion

        #region Properties
        public int BaudRate {get{return _baudRate;}}
        #endregion

        #region Constructor
        public FSKAsyncModem(int baudRate)
        {
            // check baud rate, サンプリングレート範囲 8k ~ 44k sps よって、2k ~ 11k bps -> 2400から9600bpsまで対応
            if (baudRate < 1200 || baudRate > 11000)
            {
                throw new ArgumentOutOfRangeException("baud rate", baudRate, String.Format("baud rate should be within 2400 to 9600 bps."));
            }
            _baudRate = baudRate;
            
            // setting sampling period to the signal tracer
            com.ReinforceLab.AudioModem.SignalTrace.TracerFactory.SamplingPeriod = 1.0 / _baudRate / _samplePerCycle;            
            
            _samplingRate = (_baudRate * _samplePerCycle);
            _socket       = new OpenALSocket(_samplingRate, (_samplingRate * _sampleDuration) / 1000);
            _demodulator  = new BitDemodulator();
            _modulator    = new Modulator();
            _dataRecovery = new AsyncByteReader();

            _sincFilter  = new LowPassFilter();
            _cdcFilter   = new CDCFilter();
            _sliceFilter = new SliceFilter();
            _countFilter = new PulseWidthCounterFilter();

            _audioSignal = SignalTrace.TracerFactory.CreateRecorder("Input audio");
            _sincSignal  = SignalTrace.TracerFactory.CreateRecorder("Sinc filter");
            _cdcSignal   = SignalTrace.TracerFactory.CreateRecorder("Cdc filter");
            _sliceSignal = SignalTrace.TracerFactory.CreateRecorder("Slice filter");
            _countSignal = SignalTrace.TracerFactory.CreateRecorder("Pulse width filter");
            _demodSignal = SignalTrace.TracerFactory.CreateRecorder("Demod sig");

            _thread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(_worker));
        }
        #endregion

        #region Private methods
        void _worker(object state)
        {
            System.Diagnostics.Debug.Write("Staring modem thread.\n");
            while (_socket.IsRunning)
            {
                short[] buffer = _socket.Read();
                //System.Diagnostics.Debug.Write("R" + buffer.Length + "A" + _socket.IsRunning.ToString() );
                if (buffer.Length > 0)
                {
                    var sincSig  = _sincFilter.Filter(buffer);
                    var cdcSig   = _cdcFilter.Filter(sincSig);
                    var sliceSig = _sliceFilter.Filter(cdcSig);
                    var demod    = _demodulator.Demodulate(sliceSig);
                    var countSig = _countFilter.Filter(sliceSig);
                    
                    _dataRecovery.Recovery(demod);
                    // debug
                    _audioSignal.AddValue(buffer);
                    _sincSignal.AddValue(sincSig);
                    _cdcSignal.AddValue(cdcSig);
                    _sliceSignal.AddValue(sliceSig);
                    _countSignal.AddValue(countSig);
                    _demodSignal.AddValue(demod);

                    // debug dump            
                    foreach (var sig in demod)
                        System.Diagnostics.Debug.Write(sig.ToString() + ",");
                    if (demod.Length > 0)
                        System.Diagnostics.Debug.WriteLine(String.Empty);                    
                }
                else
                {                    
                    System.Threading.Thread.Sleep(_sampleDuration / 2);
                }                
            }
            System.Diagnostics.Debug.Write("Finished modem thread.\n");
        }
        #endregion

        #region IModem メンバ
        public void Start()
        {
            _socket.Start();
            _thread.Start();
        }
        public void Stop()
        {
            _socket.Stop();
            _thread.Join();
            //_thread.Abort();
        }
        public void Write(IEnumerable<byte> data)
        {
            var modsig = _modulator.Modulate(data.ToArray<byte>());            
            _socket.Write(modsig.ToArray());            
        }
        public byte[] Read()
        {
            return _dataRecovery.Read();
        }
        #endregion        
    }*/
}
